package com.eudon.design_pattern.behavioral.visitor;

import java.util.ArrayList;
import java.util.List;

/**
 * @author eudon
 * @description 访问者模式使用示例 - 演示文件处理系统中的访问者模式应用
 * @date 2025/9/3
 * @email syd19970616@gmail.com
 * @address <a href="https://gitee.com/eudon">Gitee</a>
 */
public class Use {
    
    public static void main(String[] args) {
        System.out.println("==================== 访问者模式演示 ====================");
        System.out.println("场景：文件处理系统 - 对不同类型文件执行不相关的业务操作");
        System.out.println("优势：避免类膨胀，将操作与数据结构分离，符合开闭原则\n");
        
        // 创建不同类型的文件对象
        List<ResourceFile> files = createSampleFiles();
        
        // 创建不同的访问者（业务操作）
        Visitor extractor = new Extractor();   // 文本抽取访问者
        Visitor compressor = new Compressor();  // 文件压缩访问者
        
        // 演示场景1：对所有文件执行文本抽取操作
        demonstrateTextExtraction(files, extractor);
        
        // 演示场景2：对所有文件执行压缩操作
        demonstrateFileCompression(files, compressor);
        
        // 演示访问者模式的核心优势
        demonstrateVisitorPatternAdvantages();
        
        System.out.println("==================== 演示结束 ====================");
    }
    
    /**
     * 创建示例文件对象
     * 展示不同类型文件的创建和初始化
     */
    private static List<ResourceFile> createSampleFiles() {
        System.out.println("📁 创建示例文件对象...");
        
        List<ResourceFile> files = new ArrayList<>();
        
        // 创建PDF文件
        PdfFile pdfFile = new PdfFile("技术文档.pdf", 15, 120, true);
        files.add(pdfFile);
        System.out.println("创建PDF文件: " + pdfFile.getFileName());
        
        // 创建PPT文件
        PPTFile pptFile = new PPTFile("产品介绍.pptx", 25, 45, true, 90);
        files.add(pptFile);
        System.out.println("创建PPT文件: " + pptFile.getFileName());
        
        // 创建Word文件
        WordFile wordFile = new WordFile("项目报告.docx", 8, 12000, true, true, "2021");
        files.add(wordFile);
        System.out.println("创建Word文件: " + wordFile.getFileName());
        
        System.out.println("文件创建完成，共" + files.size() + "个文件\n");
        return files;
    }
    
    /**
     * 演示文本抽取操作
     * 展示访问者模式如何对不同类型文件执行统一的抽取操作
     */
    private static void demonstrateTextExtraction(List<ResourceFile> files, Visitor extractor) {
        System.out.println("========== 场景1：批量文本抽取操作 ==========");
        System.out.println("使用访问者: " + extractor.getVisitorName());
        System.out.println("目标：从不同格式文件中提取文本内容\n");
        
        // 对每个文件执行文本抽取操作
        // 注意：这里体现了访问者模式的核心 - 双分派机制
        // 1. 首先根据文件对象类型调用相应的accept方法
        // 2. 然后在accept方法中根据访问者类型调用相应的visit方法
        for (ResourceFile file : files) {
            file.accept(extractor); // 双分派：文件类型 + 访问者类型
        }
        
        System.out.println("所有文件的文本抽取操作已完成！\n");
    }
    
    /**
     * 演示文件压缩操作
     * 展示同样的文件对象如何接受不同的访问者执行不同的操作
     */
    private static void demonstrateFileCompression(List<ResourceFile> files, Visitor compressor) {
        System.out.println("🗜️ ========== 场景2：批量文件压缩操作 ==========");
        System.out.println("使用访问者: " + compressor.getVisitorName());
        System.out.println("目标：对不同格式文件进行优化压缩\n");
        
        // 对每个文件执行压缩操作
        // 同样的文件对象，不同的访问者，执行不同的业务逻辑
        for (ResourceFile file : files) {
            file.accept(compressor); // 双分派：文件类型 + 访问者类型
        }
        
        System.out.println("所有文件的压缩操作已完成！\n");
    }
    
    /**
     * 演示访问者模式的核心优势
     * 说明为什么使用访问者模式而不是在文件类中直接添加方法
     */
    private static void demonstrateVisitorPatternAdvantages() {
        System.out.println("========== 访问者模式的核心优势 ==========");
        
        System.out.println("传统方式的问题：");
        System.out.println("如果在PdfFile、PPTFile、WordFile中直接添加extract()、compress()方法");
        System.out.println("每次新增操作都需要修改所有文件类，违反开闭原则");
        System.out.println("文件类职责不单一，既要处理文件属性又要处理各种业务操作");
        System.out.println("类会越来越臃肿，难以维护\n");
        
        System.out.println("访问者模式的优势：");
        System.out.println("1. 开闭原则：新增操作只需添加新的访问者类，无需修改现有文件类");
        System.out.println("2. 单一职责：文件类专注于文件属性，访问者类专注于具体操作");
        System.out.println("3. 双分派机制：根据文件类型和访问者类型自动选择正确的处理方法");
        System.out.println("4. 易于扩展：可以轻松添加新的文件类型或新的操作类型\n");
        
        System.out.println("扩展示例：");
        System.out.println("新增操作：只需实现新的Visitor（如Encryptor加密器、Converter转换器）");
        System.out.println("新增文件类型：只需继承ResourceFile（如ExcelFile、ImageFile）");
        System.out.println("现有代码无需任何修改，完美符合开闭原则！\n");
        
        // 演示如何轻松扩展新操作
        demonstrateEasyExtension();
    }
    
    /**
     * 演示访问者模式的易扩展性
     * 展示如何在不修改现有代码的情况下添加新的操作
     */
    private static void demonstrateEasyExtension() {
        System.out.println("========== 扩展性演示 ==========");
        System.out.println("假设现在需要添加一个新的操作：文件信息统计");
        System.out.println("使用访问者模式，我们只需要：");
        System.out.println("创建一个新的StatisticsVisitor类实现Visitor接口");
        System.out.println("在其中实现对各种文件类型的统计逻辑");
        System.out.println("现有的PdfFile、PPTFile、WordFile类无需任何修改！\n");
        
        // 创建一个简单的统计访问者示例
        Visitor statisticsVisitor = new Visitor() {
            private int totalFiles = 0;
            private double totalSize = 0;
            
            @Override
            public void visit(PdfFile pdfFile) {
                totalFiles++;
                totalSize += pdfFile.getFileSize();
                System.out.println("统计PDF文件: " + pdfFile.getFileName() + " (" + pdfFile.getPageCount() + "页)");
            }
            
            @Override
            public void visit(PPTFile pptFile) {
                totalFiles++;
                totalSize += pptFile.getFileSize();
                System.out.println("统计PPT文件: " + pptFile.getFileName() + " (" + pptFile.getSlideCount() + "张幻灯片)");
            }
            
            @Override
            public void visit(WordFile wordFile) {
                totalFiles++;
                totalSize += wordFile.getFileSize();
                System.out.println("统计Word文件: " + wordFile.getFileName() + " (" + wordFile.getWordCount() + "字)");
            }
            
            @Override
            public String getVisitorName() {
                return "文件统计器 - 总计" + totalFiles + "个文件，" + String.format("%.1f", totalSize) + "MB";
            }
        };
        
        // 使用新的统计访问者
        List<ResourceFile> files = createSampleFiles();
        for (ResourceFile file : files) {
            file.accept(statisticsVisitor);
        }
        
        System.out.println("\n统计结果: " + statisticsVisitor.getVisitorName());
        System.out.println("我们在不修改任何现有代码的情况下，成功添加了新的统计功能！");
    }
}